<ES6>promise
简介
异步编程
Promise可以完成其他语言中类似Future和Deferred功能
异步编程的背景知识:
JS引擎是基于单线程(single-threaded)事件循环概念构建的,同一时刻只允许一个代码块在执行,代码块放在一个任务队列(job queue)中,
每当一个代码块准备执行,就会被添加到任务队列,JS引擎执行完一段代码后,事件循环会执行队列中的下一个任务,队列中的任务会从第一个执行到
最后一个。eventLoop:https://crazyaguai.github.io/2018/10/20/js-eventLoop/
事件模型
事件模型,适用于响应用户交互和完成类似的低频功能,但是对于复杂的需求不是很灵活
1 | let btn = document.querySelector('.button') |
回调模式
- 回调模式,如果嵌套了太多回调,会陷入回调地狱
Promise相关
Promise基础知识
- Promise相当于异步操作的占位符,让函数返回一个Promise
Promise生命周期: - 先处于进行中(pending)状态,此时操作未完成,它也是未处理(unsettled)的,一旦异步操作结束,Promise变为已处理(settled)状态
- 之后会进入Fulfilled(完成)或者Rejected(未成功)状态
- 内部属性[[PromiseState]]被用来表示三种状态pending\fufilled\rejected
- Promise有then()方法接收两个参数,fufilled状态调用的函数、rejected状态调用的函数
- 如果有一个对象实现了then()方法,那么称之为thenable对象,所有Promise都是thenable对象。但并非所有thenable对象都是promise
- Promise还有一个chache()方法用来接收错误,如果不给Promise添加拒绝处理程序,那么所有错误将被忽略,所以一定要添加
- 每次调用then()\cache()方法时都会创建一个任务,当promise被解决时,这些任务都会加入到一个为Promise定制的独立队列中
创建未完成的Promise
1 | function Fun() { |
- Promise执行器会立即执行,之后才会执行后续流程的代码
1 | function Fun1() { |
创建已处理的Promise
- Promise.resolve(),接收参数返回一个完成状态的Promise,不会有任何编排过程
1 | let promise = Promise.resolve(1) |
创建拒绝状态的Promise
- Promise.reject(‘error’),创建拒绝状态的Promise
1 | let promise = Promise.reject(1) |
非Promise的Thenable对象
- 非Promise的Thenable对象,如果传入一个非Promise的Thenable对象,则这些方法会创建一个新的Promise并在then()函数中调用
1 | let thenable = { |
相关应用
Thenable对象
- 可以使用Promise.resolve()或者Promise.reject()处理非Promise的Thenable对象,
- ES6之前许多库使用了thenable对象,所以如果想兼容之前已有的库,需要将Thenable对象转换为正式的Promise对象,
- 如果不确定某个对象是否为Promise对象,那么可以根据预期的结果将其传入Promise.resolve()或Promise.reject(),如果是Promise则不会有任何变化
1 | var original = Promise.resolve('我在第二行'); |
- Resolve一个thenable对象
1 | var p1 = Promise.resolve({ |
- Thenable在callback之前抛出异常
1 | // Promise rejects |
- Thenable在callback之后抛出异常
1 | // Promise resolves |
执行器错误
- 如果执行器内部抛出一个错误,那么Promise的拒绝程序就会被调用
1 | let p3 = new Promise(function (resolve,reject) { |
全局的Promise错误处理
- NodeJS中:
- unhandledRejection在一个事件中当Promise被拒绝,并且没有提供拒绝处理程序时该事件被触发
- rejectionHandled在一个事件循环后,当Promise被拒绝时,若拒绝处理程序被调用,触发该事件
1 | //拒绝原因以及被拒绝的promise作为参数被传入unhandleRejection事件处理程序 |
浏览器环境的拒绝处理
- unhandledrejection:当一个Promise被拒绝并且没有提供拒绝处理时触发
- rejectionhandled:在一个事件循环后,当Promise被拒绝时,若拒绝处理程序被调用,则触发该事件
1 | //用DOM0级标记法onunhandledrejection和onrejectionhandled |
串联Promise
- 每次调用then()、cache()方法,实际上创建并且返回了另一个Promise,当只有第一个Promise完成或者被拒绝后,第二个才会被解决
1 | let p7 = new Promise((resolve, reject) => { |
- 务必在Promise的结尾有一个处理拒绝的程序,以便能够正确处理所有的错误
Promise的链返回值
- Promise中返回一个值可以沿着这条链传递数据
- 如果返回的是Promise对象,那么要看返回的Promise怎么处理
- 响应多个Promise
Promise.all()
- 只有迭代中所有Promise都解决后才被解决
- 如果有一个被拒绝,那么返回的Promise就立即被拒绝
Promise.race()
- 只要有一个被解决返回,Promise就被解决
自Promise继承
- 定义自己的Promise来扩展内建Promise功能
- 由于MyPromise.resolve()和MyPromise.reject()通过Symbol.species属性决定返回Promise类型,所以无论传什么值,都会返回MyPromise实例
1 | class MyPromise extends Promise{ |
Promise的异步执行
- 对已完成的promise执行then,此时会执行then的操作
1 | const promise = new Promise((resolve,reject)=>{ |
- then里面不返回新的promise
1 | new Promise((resolve,reject)=>{ |
then的嵌套
需要返回一个新的promise实例才可以等resolve之后回调
错误处理,catch也会返回promise实例,后面的then和catch也会执行
1 | new Promise((resolve, reject) => { |
- promise.all 与 map 连用
1 | let arr = [1,2,3] |
- promise实现队列,使用.then返回新的promise实例
1 | let arr = [1,2,3,4] |
- promise.resolve
1 | Promise.resolve().then(res=>{ |